#pragma once

#include "LoggedTestSuite.h"

namespace CO { namespace SpiFoundation { namespace RoomFW {

class TimerTestAO : public SpiFoundation::RoomFW::ActiveObject
{
public:
	typedef ::boost::shared_ptr<TimerTestAO> Ptr;

	//
	// Test Cases
	//
	enum TestCase
	{
		None,
		OneShot,
		MultiOneShot,
		Repeat
	};

	void setTestCase(TestCase testCase);

	std::string testErrorMessage;

	//
	// Enumeration value for each port.
	//
	enum PortEnum 
	{
		PORT_COUNT,				// Number of user defined ports.
		PORT_TIMER = PORT_COUNT // Port index used to handle timer messages.
	};

	//
	// Static array used to assign port priorities in the same order ports are
	// named above.  Must have PORT_COUNT + 1 Elements.  Last element for timer.
	//
	static const PortPriority PortPriorities[];
	static const size_t PortPrioritiesSize;

	//
	// Constructor/Destructor.
	//
	TimerTestAO(void);
	virtual ~TimerTestAO(void);

	//
	// IActiveObject overrides.
	//
	virtual const char* getPortName(size_t portIndex) const;
	SpiFoundation::RoomFW::IContractCheckerSPC getContractChecker(SpiFoundation::RoomFW::PortIndex portIndex) const;
	virtual SpiFoundation::RoomFW::ObjectId getObjectId(void) const;
	virtual const char* getObjectName(void) const;

protected:

	//
	// Thread overrides.
	//
	virtual void onStart(void);
	virtual void onStop(void);

	//
	// ActiveObject override.
	//
	virtual void handle(SpiFoundation::RoomFW::RoomMessageSP message);

private:

	int diffTime();

	//
	// Private attributes.
	//
	TestCase testCase_;
	RoomTimer::TimerId timerId_;
	std::list<RoomTimer::TimerId> timerIdList_;
	DWORD timeout_;
	size_t count_;
	_timeb startTime_;
	DWORD timerResolution_;
	size_t timeoutCount_;
	static const size_t MultiOneShotTimerCount =
#if ACTIVE_OBJECT_TIMER_THREADS
		80;
#else
		60;
#endif
};

class TimerTestSuite : public LoggedTestSuite
{
public:
	TimerTestSuite();
	~TimerTestSuite();
	
protected:

	virtual void setup();
	virtual void tear_down();

private:

	void empty(void);
	void oneShot(void);
	void multiOneShot(void);
	void repeat(void);
	void starvation(void);

	//
	// Test: RobotTimeout
	//
	// Description:  This test is based on the robot implementation that has
	//					a high rate of message input and sets and cancels a
	//					single timer a lot.
	//				For this test we'll alternate between message one setting
	//					a long duration timer and message two canceling it.
	//				We're really trying to ensure that the ActiveObject is
	//					Managing its timers correctly.  We'll do that by peeking
	//					under the hood to ensure it hasn't started any extra timer threads.
	//
	void RobotTimeout();

	//
	// Test:  MessageFlood
	//
	// Description:  Test what happens when an object is flooded with messages and each
	//				  Message starts a short duration timer.
	//				Send 60 messages that start a timer followed by some large number of
	//					pairs of messages that sleep for X and start a timer for X
	//					to ensure it stays in the message loop with a full timer queue
	//				Verify the correct number of timeouts and that no timer threads were
	//				used.  Tests RoomTimer::pulse() correctness.
	//
	void MessageFlood();


	TimerTestAO testObj_;
};

}}}
